package com.wutianyi.controller;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.channels.Channels;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.google.appengine.api.blobstore.BlobInfo;
import com.google.appengine.api.blobstore.BlobInfoFactory;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.blobstore.UploadOptions;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileService;
import com.google.appengine.api.files.FileServiceFactory;
import com.google.appengine.api.files.FileWriteChannel;
import com.google.appengine.api.images.Image;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;
import com.google.appengine.api.images.Transform;
import com.wutianyi.entity.EntityTypeEnum;

/**
 * @author hanjiewu 上传的逻辑
 */
@Controller
public class UploadController {
	
	@Autowired
	private BlobInfoFactory blobInfoFactory;
	
	@RequestMapping("/uploadurl.do")
	public ResponseEntity<String> getUploadUrl(int redirect) {
		String url = BlobstoreServiceFactory.getBlobstoreService().createUploadUrl(
				"/upload.do?redirect=" + redirect,
				UploadOptions.Builder.withMaxUploadSizeBytesPerBlob(10000000));
		HttpHeaders responseHeader = new HttpHeaders();
		responseHeader.setContentType(MediaType.TEXT_PLAIN);
		
		return new ResponseEntity<String>(url, responseHeader, HttpStatus.OK);
	}
	
	@RequestMapping(value = "/upload.do", method = RequestMethod.POST)
	public ResponseEntity<String> upload(HttpServletRequest request, int redirect)
			throws URISyntaxException {
		String md5Key = getBlobFileMd5(request);
		HttpHeaders headers = new HttpHeaders();
		if (StringUtils.isNotBlank(md5Key)) {
			
			if (1 == redirect) {
				headers = new HttpHeaders();
				headers.setLocation(new URI("/serve.do?key=" + md5Key));
				return new ResponseEntity<String>(headers, HttpStatus.TEMPORARY_REDIRECT);
			} else {
				headers.setContentType(MediaType.TEXT_PLAIN);
				String post = "";
				if (request.getServerPort() != 80) {
					post = ":" + request.getServerPort();
				}
				
				String resourceUrl = request.getScheme() + "://" + request.getServerName()
						+ request.getContextPath() + post + "/serve.do?key=" + md5Key;
				return new ResponseEntity<String>(resourceUrl, headers, HttpStatus.OK);
			}
		}
		return new ResponseEntity<String>(HttpStatus.FORBIDDEN);
	}
	
	private String getBlobFileMd5(HttpServletRequest request) {
		BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
		
		Map<String, List<BlobKey>> mapBlobs = BlobstoreServiceFactory.getBlobstoreService()
				.getUploads(request);
		
		List<BlobKey> blobs = null;
		if (mapBlobs.size() > 0) {
			for (List<BlobKey> bs : mapBlobs.values()) {
				blobs = bs;
				break;
			}
		}
		if (null != blobs && !blobs.isEmpty()) {
			BlobKey blobkey = blobs.get(0);
			
			BlobInfo blobInfo = blobInfoFactory.loadBlobInfo(blobkey);
			String md5Key = blobInfo.getMd5Hash();
			// 判断上传的内容是否已经存在
			Key key = KeyFactory.createKey(EntityTypeEnum.BlobKey.name(), md5Key);
			Query query = new Query(key);
			int exist = DatastoreServiceFactory.getDatastoreService().prepare(query)
					.asList(FetchOptions.Builder.withLimit(1)).size();
			if (exist != 0) {
				blobstoreService.delete(blobkey);
			} else {
				Entity entity = new Entity(key);
				entity.setProperty("blob-key", blobkey.getKeyString());
				DatastoreServiceFactory.getDatastoreService().put(entity);
				makeResizeImage(blobkey, 460, 253, md5Key);
				makeResizeImage(blobkey, 115, 64, md5Key);
			}
			return md5Key;
		}
		return null;
	}
	
	@RequestMapping("/serve.jpg")
	public void serveJpg(HttpServletResponse response, String key) throws IOException {
		serve(response, key);
	}
	
	@RequestMapping("/serve.do")
	public void serve(HttpServletResponse response, String key) throws IOException {
		Key bKey = KeyFactory.createKey(EntityTypeEnum.BlobKey.toString(), key);
		try {
			Entity entity = DatastoreServiceFactory.getDatastoreService().get(bKey);
			BlobKey k = new BlobKey((String) entity.getProperty("blob-key"));
			
			// ImagesService imagesService =
			// ImagesServiceFactory.getImagesService();
			// Image image = ImagesServiceFactory.makeImageFromBlob(k);
			// Transform resize = ImagesServiceFactory.makeResize(width,
			// height);
			// image = imagesService.applyTransform(resize, image);
			// response.getOutputStream().write(image.getImageData());
			BlobstoreServiceFactory.getBlobstoreService().serve(k, response);
			
		} catch (EntityNotFoundException e) {
			response.setStatus(HttpServletResponse.SC_NOT_FOUND);
		}
	}
	
	private void makeResizeImage(BlobKey k, int width, int height, String key) {
		try {
			ImagesService imagesService = ImagesServiceFactory.getImagesService();
			Image image = ImagesServiceFactory.makeImageFromBlob(k);
			Transform resize = ImagesServiceFactory.makeResize(width, height);
			image = imagesService.applyTransform(resize, image);
			FileService fileService = FileServiceFactory.getFileService();
			AppEngineFile file = fileService.createNewBlobFile("application/octet-stream");
			FileWriteChannel writeChannel = fileService.openWriteChannel(file, true);
			OutputStream output = Channels.newOutputStream(writeChannel);
			byte[] bytes = image.getImageData();
			output.write(bytes);
			output.close();
			writeChannel.closeFinally();
			BlobKey blobKey = fileService.getBlobKey(file);
			Key kk = KeyFactory
					.createKey(EntityTypeEnum.BlobKey.name(), key + width + "x" + height);
			Entity entity = new Entity(kk);
			entity.setProperty("blob-key", blobKey.getKeyString());
			entity.setProperty("scale", "1");
			DatastoreServiceFactory.getDatastoreService().put(entity);
		} catch (Exception e) {

		}
	}
	
	public BlobInfoFactory getBlobInfoFactory() {
		return blobInfoFactory;
	}
	
	public void setBlobInfoFactory(BlobInfoFactory blobInfoFactory) {
		this.blobInfoFactory = blobInfoFactory;
	}
	
}
